package com.smile.commons.gps;

import com.smile.commons.gps.domain.*;
import com.smile.commons.gps.domain.kml.KmlParams;
import com.smile.commons.gps.domain.kml.RoutePointInfo;
import lombok.Data;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 基于 mzhx.kmz 模板的面状航线文件生成工具类
 * 提供从边界点坐标生成标准 KMZ 航线文件的完整功能
 * 
 * @author System
 * @since 2024-09-18
 */
public class PlanarAirlineKmzGenerator {

    /**
     * 面状航线生成配置模板
     */
    @Data
    public static class AirlineTemplate {
        /** 模板名称 */
        private String templateName = "mzhx_template";
        
        /** 模板描述 */
        private String description = "基于mzhx.kmz的面状航线模板";
        
        /** 默认飞行高度(米) */
        private BigDecimal defaultFlightHeight = new BigDecimal("100");
        
        /** 默认飞行速度(m/s) */
        private Double defaultSpeed = 5.0;
        
        /** 默认航向重叠率(%) */
        private Integer defaultOverlapH = 80;
        
        /** 默认旁向重叠率(%) */
        private Integer defaultOverlapW = 70;
        
        /** 默认航线方向(度) */
        private Integer defaultDirection = 0;
        
        /** 默认边界外扩距离(米) */
        private Integer defaultMargin = 30;
        
        /** 是否启用高德地图优化 */
        private Boolean gaodeOptimized = true;
        
        /** 相机配置参数 */
        private CameraConfig cameraConfig = new CameraConfig();
        
        /** 航线生成策略 */
        private String generationStrategy = "DENSE_GRID"; // STANDARD, DENSE_GRID, BOUNDARY_OPTIMIZED
    }
    
    /**
     * 相机配置参数
     */
    @Data
    public static class CameraConfig {
        /** 焦距(mm) */
        private Double focalLength = 24.0;
        
        /** 传感器宽度(mm) */
        private Double sensorWidth = 36.0;
        
        /** 传感器高度(mm) */
        private Double sensorHeight = 24.0;
        
        /** 图像宽度(像素) */
        private Integer imageWidth = 4000;
        
        /** 图像高度(像素) */
        private Integer imageHeight = 3000;
    }
    
    /**
     * 航线生成结果
     */
    @Data
    public static class AirlineGenerationResult {
        /** 生成的 KMZ 文件路径 */
        private String kmzFilePath;
        
        /** 航点数量 */
        private Integer waypointCount;
        
        /** 预估飞行时间(分钟) */
        private Double estimatedFlightTime;
        
        /** 预估飞行距离(米) */
        private Double estimatedDistance;
        
        /** 覆盖面积(平方米) */
        private Double coverageArea;
        
        /** 航线摘要信息 */
        private String summary;
        
        /** 使用的配置模板 */
        private AirlineTemplate usedTemplate;
    }

    /**
     * 基于边界点生成面状航线 KMZ 文件（使用默认模板）
     * 
     * @param boundaryPoints 边界点列表
     * @param outputFileName 输出文件名（不含扩展名）
     * @return 航线生成结果
     * @throws IOException 文件操作异常
     */
    public static AirlineGenerationResult generatePlanarAirlineKmz(
            List<CoordinatePointReq> boundaryPoints, 
            String outputFileName) throws IOException {
        
        AirlineTemplate defaultTemplate = new AirlineTemplate();
        return generatePlanarAirlineKmz(boundaryPoints, outputFileName, defaultTemplate);
    }

    /**
     * 基于边界点和自定义模板生成面状航线 KMZ 文件
     * 
     * @param boundaryPoints 边界点列表
     * @param outputFileName 输出文件名（不含扩展名）
     * @param template 航线生成模板
     * @return 航线生成结果
     * @throws IOException 文件操作异常
     */
    public static AirlineGenerationResult generatePlanarAirlineKmz(
            List<CoordinatePointReq> boundaryPoints, 
            String outputFileName, 
            AirlineTemplate template) throws IOException {
        
        System.out.println("=== 基于 mzhx.kmz 模板生成面状航线 ===");
        System.out.println("模板: " + template.getTemplateName());
        System.out.println("边界点数量: " + boundaryPoints.size());
        
        // 1. 验证输入参数
        validateInputs(boundaryPoints, outputFileName, template);
        
        // 2. 创建航线配置
        PlanarAirlineGenerator.AirlineConfig config = createAirlineConfig(template);
        
        // 3. 生成面状航线
        PlanarAirlineService.PlanarAirlineResult airlineResult = 
            PlanarAirlineService.generateCompletePlanarAirline(boundaryPoints, config, 15.0);
        
        // 4. 创建 KMZ 文件
        String kmzPath = generateKmzFromTemplate(outputFileName, airlineResult, template);
        
        // 5. 计算统计信息
        AirlineGenerationResult result = calculateStatistics(
            kmzPath, airlineResult, template, boundaryPoints);
        
        System.out.println("航线生成完成: " + result.getSummary());
        return result;
    }

    /**
     * 批量生成多个区域的航线文件
     * 
     * @param regions 多个区域的边界点列表
     * @param baseFileName 基础文件名
     * @param template 航线模板
     * @return 生成结果列表
     * @throws IOException 文件操作异常
     */
    public static List<AirlineGenerationResult> generateBatchAirlines(
            List<List<CoordinatePointReq>> regions, 
            String baseFileName, 
            AirlineTemplate template) throws IOException {
        
        List<AirlineGenerationResult> results = new ArrayList<>();
        
        for (int i = 0; i < regions.size(); i++) {
            String fileName = baseFileName + "_region_" + (i + 1);
            AirlineGenerationResult result = generatePlanarAirlineKmz(
                regions.get(i), fileName, template);
            results.add(result);
        }
        
        return results;
    }

    /**
     * 根据不同飞行需求创建预设模板
     */
    public static class TemplatePresets {
        
        /**
         * 高精度测绘模板
         */
        public static AirlineTemplate createMappingTemplate() {
            AirlineTemplate template = new AirlineTemplate();
            template.setTemplateName("mzhx_mapping_template");
            template.setDescription("高精度测绘航线模板");
            template.setDefaultFlightHeight(new BigDecimal("60"));
            template.setDefaultSpeed(3.0);
            template.setDefaultOverlapH(90);
            template.setDefaultOverlapW(85);
            template.setDefaultMargin(0);
            template.setGaodeOptimized(true);
            template.setGenerationStrategy("DENSE_GRID");
            
            // 高精度相机配置
            CameraConfig camera = new CameraConfig();
            camera.setFocalLength(50.0);
            camera.setImageWidth(8000);
            camera.setImageHeight(6000);
            template.setCameraConfig(camera);
            
            return template;
        }
        
        /**
         * 快速巡检模板
         */
        public static AirlineTemplate createInspectionTemplate() {
            AirlineTemplate template = new AirlineTemplate();
            template.setTemplateName("mzhx_inspection_template");
            template.setDescription("快速巡检航线模板");
            template.setDefaultFlightHeight(new BigDecimal("120"));
            template.setDefaultSpeed(8.0);
            template.setDefaultOverlapH(70);
            template.setDefaultOverlapW(60);
            template.setDefaultMargin(50);
            template.setGaodeOptimized(false);
            template.setGenerationStrategy("STANDARD");
            
            return template;
        }
        
        /**
         * 植保作业模板
         */
        public static AirlineTemplate createAgricultureTemplate() {
            AirlineTemplate template = new AirlineTemplate();
            template.setTemplateName("mzhx_agriculture_template");
            template.setDescription("植保作业航线模板");
            template.setDefaultFlightHeight(new BigDecimal("15"));
            template.setDefaultSpeed(6.0);
            template.setDefaultOverlapH(20);
            template.setDefaultOverlapW(15);
            template.setDefaultMargin(5);
            template.setGaodeOptimized(true);
            template.setGenerationStrategy("BOUNDARY_OPTIMIZED");
            
            return template;
        }
        
        /**
         * 应急搜救模板
         */
        public static AirlineTemplate createSearchRescueTemplate() {
            AirlineTemplate template = new AirlineTemplate();
            template.setTemplateName("mzhx_search_rescue_template");
            template.setDescription("应急搜救航线模板");
            template.setDefaultFlightHeight(new BigDecimal("80"));
            template.setDefaultSpeed(10.0);
            template.setDefaultOverlapH(60);
            template.setDefaultOverlapW(50);
            template.setDefaultMargin(100);
            template.setGaodeOptimized(false);
            template.setGenerationStrategy("STANDARD");
            
            return template;
        }
    }

    /**
     * 验证输入参数
     */
    private static void validateInputs(List<CoordinatePointReq> boundaryPoints, 
                                     String outputFileName, 
                                     AirlineTemplate template) {
        if (boundaryPoints == null || boundaryPoints.size() < 3) {
            throw new IllegalArgumentException("边界点数量至少需要3个");
        }
        
        if (outputFileName == null || outputFileName.trim().isEmpty()) {
            throw new IllegalArgumentException("输出文件名不能为空");
        }
        
        if (template == null) {
            throw new IllegalArgumentException("航线模板不能为空");
        }
        
        // 验证边界点的有效性
        for (CoordinatePointReq point : boundaryPoints) {
            if (point.getLatitude() == null || point.getLongitude() == null) {
                throw new IllegalArgumentException("边界点坐标不能为空");
            }
        }
    }

    /**
     * 根据模板创建航线配置
     */
    private static PlanarAirlineGenerator.AirlineConfig createAirlineConfig(AirlineTemplate template) {
        PlanarAirlineGenerator.AirlineConfig config = new PlanarAirlineGenerator.AirlineConfig();
        
        config.setFlightHeight(template.getDefaultFlightHeight());
        config.setOverlapH(template.getDefaultOverlapH());
        config.setOverlapW(template.getDefaultOverlapW());
        config.setDirection(template.getDefaultDirection());
        config.setMargin(template.getDefaultMargin());
        config.setGaodeOptimized(template.getGaodeOptimized());
        
        // 相机参数配置
        CameraConfig camera = template.getCameraConfig();
        config.setFocalLength(camera.getFocalLength());
        config.setSensorWidth(camera.getSensorWidth());
        config.setSensorHeight(camera.getSensorHeight());
        config.setImageWidth(camera.getImageWidth());
        config.setImageHeight(camera.getImageHeight());
        
        return config;
    }

    /**
     * 基于模板生成 KMZ 文件
     */
    private static String generateKmzFromTemplate(String outputFileName, 
                                                PlanarAirlineService.PlanarAirlineResult airlineResult, 
                                                AirlineTemplate template) throws IOException {
        
        // 创建 KML 参数
        KmlParams kmlParams = new KmlParams();
        
        // 转换航线数据为 RoutePointInfo 格式
        List<RoutePointInfo> routePoints = convertToRoutePoints(
            airlineResult.getFlightPath(), template);
        kmlParams.setRoutePointList(routePoints);
        
        // 设置航线参数
        kmlParams.setAutoFlightSpeed(new BigDecimal(template.getDefaultSpeed()));
        kmlParams.setGlobalHeight(template.getDefaultFlightHeight());
        kmlParams.setTemplateType("waypoint");
        kmlParams.setFinishAction("goHome");
        kmlParams.setExitOnRcLostAction("goHome");
        kmlParams.setAirlineHeightType(0); // 默认使用相对起飞点高度
        kmlParams.setDroneType(100); // 默认无人机类型
        kmlParams.setSubDroneType(1); // 默认子类型
        kmlParams.setPayloadType(1); // 默认负载类型
        kmlParams.setPayloadPosition(0); // 默认负载位置
        kmlParams.setGlobalShootHeight(template.getDefaultFlightHeight()); // 被摄面高度，使用飞行高度
        
        // 初始化航点转弯参数
        WaypointTurnReq waypointTurnReq = new WaypointTurnReq();
        waypointTurnReq.setWaypointTurnMode("toPointAndStopWithDiscontinuityCurvature"); // 直线飞行，飞行器到点停
        waypointTurnReq.setUseStraightLine(1); // 航段轨迹尽量贴合两点连线
        waypointTurnReq.setWaypointTurnDampingDist(1.0); // 默认转弯截距
        kmlParams.setWaypointTurnReq(waypointTurnReq);
        
        // 初始化航点偏航角参数
        WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq();
        waypointHeadingReq.setWaypointHeadingMode("followWayline"); // 沿航线方向
        kmlParams.setWaypointHeadingReq(waypointHeadingReq);
        
        // 初始化建图航拍参数
        MappingTypeReq mappingTypeReq = new MappingTypeReq();
        mappingTypeReq.setCollectionMethod("ortho"); // 正射采集
        mappingTypeReq.setLensType("camera"); // 相机镜头
        mappingTypeReq.setOverlapH(80); // 航向重叠率80%
        mappingTypeReq.setOverlapW(70); // 旁向重叠率70%
        mappingTypeReq.setElevationOptimizeEnable(0); // 默认不开启高程优化
        mappingTypeReq.setShootType("time"); // 等时间拍照
        mappingTypeReq.setDirection("0"); // 航线方向
        mappingTypeReq.setMargin("30"); // 测区外扩距离
        mappingTypeReq.setCoordinates(new ArrayList<>()); // 坐标列表
        kmlParams.setMappingTypeReq(mappingTypeReq);
        
        // 创建扩展参数
        RouteFileUtils.KmlParamsExtension extension = new RouteFileUtils.KmlParamsExtension();
        extension.setGlobalTransitionalSpeed(new BigDecimal("3.0"));
        extension.setGlobalRTHHeight(new BigDecimal("120"));
        extension.setTakeOffSecurityHeight(new BigDecimal("20"));
        
        // 生成 KMZ 文件
        String finalFileName = outputFileName + "_" + template.getTemplateName() + "_" + System.currentTimeMillis();
        return RouteFileUtils.buildKmz(extension, finalFileName, kmlParams);
    }

    /**
     * 转换航点数据格式
     */
    private static List<RoutePointInfo> convertToRoutePoints(List<CoordinatePointReq> flightPath, 
                                                           AirlineTemplate template) {
        List<RoutePointInfo> routePoints = new ArrayList<>();
        
        for (int i = 0; i < flightPath.size(); i++) {
            CoordinatePointReq point = flightPath.get(i);
            RoutePointInfo routePoint = new RoutePointInfo();
            
            routePoint.setRoutePointIndex(i);
            routePoint.setLatitude(point.getLatitude().doubleValue());
            routePoint.setLongitude(point.getLongitude().doubleValue());
            routePoint.setHeight(point.getHeight());
            routePoint.setSpeed(template.getDefaultSpeed());
            routePoint.setUseGlobalHeight("false");
            routePoint.setUseGlobalSpeed("false");
            
            // 根据航点位置添加特殊动作
            if (i == 0) {
                // 起始点：起飞
                addTakeoffActions(routePoint);
            } else if (i == flightPath.size() - 1) {
                // 终点：拍照并准备返航
                addLandingActions(routePoint);
            } else {
                // 中间点：拍照
                addPhotoActions(routePoint);
            }
            
            routePoints.add(routePoint);
        }
        
        return routePoints;
    }

    /**
     * 添加起飞动作
     */
    private static void addTakeoffActions(RoutePointInfo routePoint) {
        List<PointActionReq> actions = new ArrayList<>();
        // 这里可以添加具体的起飞动作配置
        routePoint.setActions(actions);
    }

    /**
     * 添加拍照动作
     */
    private static void addPhotoActions(RoutePointInfo routePoint) {
        List<PointActionReq> actions = new ArrayList<>();
        // 这里可以添加具体的拍照动作配置
        routePoint.setActions(actions);
    }

    /**
     * 添加降落动作
     */
    private static void addLandingActions(RoutePointInfo routePoint) {
        List<PointActionReq> actions = new ArrayList<>();
        // 这里可以添加具体的降落动作配置
        routePoint.setActions(actions);
    }

    /**
     * 计算航线统计信息
     */
    private static AirlineGenerationResult calculateStatistics(String kmzPath, 
                                                             PlanarAirlineService.PlanarAirlineResult airlineResult, 
                                                             AirlineTemplate template,
                                                             List<CoordinatePointReq> boundaryPoints) {
        
        AirlineGenerationResult result = new AirlineGenerationResult();
        result.setKmzFilePath(kmzPath);
        result.setWaypointCount(airlineResult.getFlightPath().size());
        result.setUsedTemplate(template);
        
        // 计算飞行距离
        double totalDistance = calculateTotalDistance(airlineResult.getFlightPath());
        result.setEstimatedDistance(totalDistance);
        
        // 计算飞行时间（距离/速度 + 悬停时间）
        double flightTime = (totalDistance / template.getDefaultSpeed()) / 60.0; // 转换为分钟
        result.setEstimatedFlightTime(flightTime);
        
        // 计算覆盖面积
        double area = calculatePolygonArea(boundaryPoints);
        result.setCoverageArea(area);
        
        // 生成摘要
        String summary = String.format(
            "航线生成完成 - 航点数:%d, 距离:%.0fm, 时间:%.1fmin, 面积:%.0fm²", 
            result.getWaypointCount(), 
            result.getEstimatedDistance(), 
            result.getEstimatedFlightTime(), 
            result.getCoverageArea()
        );
        result.setSummary(summary);
        
        return result;
    }

    /**
     * 计算航线总距离
     */
    private static double calculateTotalDistance(List<CoordinatePointReq> flightPath) {
        if (flightPath.size() < 2) return 0;
        
        double totalDistance = 0;
        for (int i = 1; i < flightPath.size(); i++) {
            totalDistance += calculateDistance(flightPath.get(i-1), flightPath.get(i));
        }
        return totalDistance;
    }

    /**
     * 计算两点距离（哈弗辛公式）
     */
    private static double calculateDistance(CoordinatePointReq point1, CoordinatePointReq point2) {
        double lat1 = Math.toRadians(point1.getLatitude().doubleValue());
        double lon1 = Math.toRadians(point1.getLongitude().doubleValue());
        double lat2 = Math.toRadians(point2.getLatitude().doubleValue());
        double lon2 = Math.toRadians(point2.getLongitude().doubleValue());
        
        double deltaLat = lat2 - lat1;
        double deltaLon = lon2 - lon1;
        
        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                   Math.cos(lat1) * Math.cos(lat2) *
                   Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return 6378137.0 * c; // 地球半径 * 弧度
    }

    /**
     * 计算多边形面积
     */
    private static double calculatePolygonArea(List<CoordinatePointReq> polygon) {
        if (polygon.size() < 3) return 0;
        
        double area = 0;
        int n = polygon.size();
        
        for (int i = 0; i < n; i++) {
            int j = (i + 1) % n;
            double lat1 = Math.toRadians(polygon.get(i).getLatitude().doubleValue());
            double lon1 = Math.toRadians(polygon.get(i).getLongitude().doubleValue());
            double lat2 = Math.toRadians(polygon.get(j).getLatitude().doubleValue());
            double lon2 = Math.toRadians(polygon.get(j).getLongitude().doubleValue());
            
            area += (lon2 - lon1) * (2 + Math.sin(lat1) + Math.sin(lat2));
        }
        
        area = Math.abs(area) * 6378137.0 * 6378137.0 / 2.0;
        return area;
    }

    /**
     * 演示方法：展示各种模板的使用
     */
    public static void demonstrateTemplateUsage() {
        System.out.println("=== mzhx.kmz 模板航线生成演示 ===");
        
        // 创建示例边界点（杭州西湖区域）
        List<CoordinatePointReq> boundaryPoints = createSampleBoundary();
        
        try {
            // 演示1：使用默认模板
            System.out.println("\n1. 使用默认模板生成航线");
            AirlineGenerationResult result1 = generatePlanarAirlineKmz(
                boundaryPoints, "sample_default");
            System.out.println("结果: " + result1.getSummary());
            
            // 演示2：使用高精度测绘模板
            System.out.println("\n2. 使用高精度测绘模板");
            AirlineTemplate mappingTemplate = TemplatePresets.createMappingTemplate();
            AirlineGenerationResult result2 = generatePlanarAirlineKmz(
                boundaryPoints, "sample_mapping", mappingTemplate);
            System.out.println("结果: " + result2.getSummary());
            
            // 演示3：使用快速巡检模板
            System.out.println("\n3. 使用快速巡检模板");
            AirlineTemplate inspectionTemplate = TemplatePresets.createInspectionTemplate();
            AirlineGenerationResult result3 = generatePlanarAirlineKmz(
                boundaryPoints, "sample_inspection", inspectionTemplate);
            System.out.println("结果: " + result3.getSummary());
            
        } catch (Exception e) {
            System.err.println("演示失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 创建示例边界点
     */
    private static List<CoordinatePointReq> createSampleBoundary() {
        List<CoordinatePointReq> points = new ArrayList<>();
        
        // 杭州西湖附近的示例区域
        points.add(createPoint(30.250000, 120.140000));
        points.add(createPoint(30.250000, 120.150000));
        points.add(createPoint(30.259000, 120.150000));
        points.add(createPoint(30.259000, 120.140000));
        
        return points;
    }

    /**
     * 创建坐标点
     */
    private static CoordinatePointReq createPoint(double lat, double lon) {
        CoordinatePointReq point = new CoordinatePointReq();
        point.setLatitude(new BigDecimal(lat));
        point.setLongitude(new BigDecimal(lon));
        point.setHeight(new BigDecimal("120"));
        return point;
    }

    /**
     * 主方法：用于测试
     */
    public static void main(String[] args) {
        demonstrateTemplateUsage();
    }
}